package com.RomaRemez;

import java.util.Scanner;

/**
 * Класс <code>Divide</code> предназначен для отображения
 * процесса деления двух целых чисел в столбик.
 *
 * @version  1.08 06.10.2013
 * @author Roman Remez
 */
public class Divide{
    public static void main(String[] args) {
        int dividend = input("dividend", false);
        int divisor = input("divisor", true);

        System.out.printf("%d | %d%n", dividend, divisor);

        int[] dividendAsArray = numberAsArray(String.valueOf(Math.abs(dividend)));

        int resultSign = getResultSign(dividend, divisor);
        double result = resultSign * divide(dividendAsArray, Math.abs(divisor));

        printResult(result);
    }

    /**
     *  Method <code>divide</code> returns final result;
     */
    private static double divide(int[] dividendAsArray, int divisor) {
        int currentRemainder = 0;
        int currentResult = 0;
        int quotientPart = 0;
        for (int elem : dividendAsArray) {
            currentRemainder = currentRemainder * 10 + elem;
            currentResult = currentRemainder / divisor;

            quotientPart = quotientPart * 10 + currentResult;
            if (currentRemainder >= divisor) {
                printStep(currentRemainder, currentResult, divisor, String.valueOf(quotientPart));
            }
            currentRemainder %= divisor;
        }
        if (currentRemainder == 0) {
            return quotientPart;
        }
        else {
            return quotientPart + findFractionalPart(divisor, currentRemainder, quotientPart);
        }
    }

    private static int[] numberAsArray(String dividendStr) {
        int dividendLength = dividendStr.length();
        int[] result = new int[dividendLength];

        for (int i = 0; i < dividendLength; i++){
            result[i] = Integer.parseInt(dividendStr.substring(i, i + 1));
        }
        return result;
    }

    /**
     * input data and return it as <code>int</code>
     */
    private static int input(String operand, boolean divisor) {
        Scanner in = new Scanner(System.in);
        int result = 0;
        String inputStr = "";
        while (true){
            try {
                System.out.printf("Enter integer %s:%n", operand);
                inputStr = in.nextLine();
                result = Integer.parseInt(inputStr);
                if ((divisor) && (0 == result)){
                    System.out.println("Enter non zero divisor please");
                } else {
                    break;
                }
            } catch (NumberFormatException e){
                System.out.println("Enter integer, please.");
            }
        }
        return result;
    }

    /**
     * method takes operands and returns 1 or -1
     * 1 for positive result, -1 for negative
     */
    private static int getResultSign(long currentDividend, int divisor) {
        int  resultSign = 1;
        if ((currentDividend / divisor) < 0) {
            resultSign = -1;
        }
        return resultSign;
    }

    /**
     * Находит дробную часть результата до 14-й цифры после запятой.
     */
    private static double findFractionalPart(int divisor, int currentDividend, int quotientPart){
        final double DIGITS_AFTER_COMMA = 1e-13;
        double currentResult = 0.0;
        double positionFinder = 1;
        int quotient = 0;
        int remainder = currentDividend % divisor;
        while ((remainder % divisor != 0) && (positionFinder > DIGITS_AFTER_COMMA )){
            positionFinder *= 0.1;
            for (int i = 0; remainder < divisor; i++){
                remainder *=10;
                if (i > 0) {positionFinder *= 0.1;}
            }

            quotient = remainder / divisor;
            printStep(remainder, quotient, divisor,
                      String.valueOf(quotientPart + currentResult));
            remainder = remainder - (quotient * divisor);
            currentResult += quotient * positionFinder;
        }
        /*print last step*/
        printStep(quotient * divisor, quotient, divisor,
                String.valueOf(quotientPart + currentResult));
        return currentResult;
    }

    /**
     * Выводит в консоль текущий шаг деления в столбик
     * из-за неточности типа <code>double</code> вывод может
     * показыватсься не корректно, что не влияет на числовой результат
     */
    private static void printStep(int currentRemainder, int currentResult,
                                  int divisor, String quotientPart){
        String spaces = " ";
        for (int i = 0; i < quotientPart.length(); i++){
            spaces += " ";
        }
        System.out.printf("%s_%d%n%s %d | %s%n", spaces, currentRemainder, spaces,
                currentResult * divisor, quotientPart);
    }

    /**
     *  Prints final result.
     */
    private static void printResult(double result){
        System.out.println("------------\n" + result);
    }
}
